﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Data.Entity;
using TeaLightV5.Foundation.BL;
using TeaLightV5.Foundation.Sal.DataRequests;
using TeaLightV5.Foundation.Sal.DataResponses;
using TeaLightV5.Foundation.Sal.Interfaces;
using TeaLightV5.Foundation.Server.DataSchema;
using TeaLightV5.Foundation.Utilities;

namespace TeaLightV5.Foundation.Server.Synchronization
{
    public abstract class SyncObject<Tdto, Trdto, Tqdto, Te, Tkey>
        where Tdto : IServiceObject<Tkey>, new()
        where Trdto : DataResponse<Tdto>, new()
        where Tqdto : DataRequest<Tdto>
        where Te : class, IEntity<Tkey>, ISyncableEntity, new()
    {
        string _entitySetName;

        protected SyncObject(string entitySetName)
        {
            _entitySetName = entitySetName;
        }

        protected abstract DbContextBase<Tkey> CreateContext();

        protected abstract Tdto FromDatabase(Te Item);

        protected abstract void FromService(Tdto item, Te entity);

        public Trdto GetByModifiedDate(DateTime fromDate)
        {
            try
            {
                using (DbContextBase<Tkey> entities = CreateContext())
                {

                    Collection<Tdto> list = new Collection<Tdto>();

                    DbSet<Te> set = entities.Set<Te>();

                    foreach (var item in (from i in (set) where i.Modified >= fromDate select i))
                    {
                        list.Add(FromDatabase(item));
                    }

                    return new Trdto()
                    {
                        Data = list,
                        IsError = false,
                        IsLast = true
                    };
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
                return new Trdto()
                {
                    IsError = true
                };
            }
        }

        public DeletedRowDataResponse<Tkey> GetDeletedRowsByModifiedDate(DateTime fromDate)
        {
            try
            {
                using (DbContextBase<Tkey> entities = CreateContext())
                {

                    Collection<Tkey> list = new Collection<Tkey>();

                    foreach (var item in (from i in (entities.Set<DeletedRow<Tkey>>())
                                          where i.Modified >= fromDate
                                          && i.TableName == _entitySetName
                                          select i))
                    {
                        list.Add(item.RowId);
                    }

                    return new DeletedRowDataResponse<Tkey>()
                    {
                        Data = list,
                        IsError = false,
                        IsLast = true
                    };
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
                return new DeletedRowDataResponse<Tkey>()
                {
                    IsError = true
                };
            }
        }

        public void Update(Tqdto data)
        {
            try
            {
                using (DbContextBase<Tkey> entities = CreateContext())
                {
                    DbSet<Te> set = entities.Set<Te>();

                    foreach (Tdto item in data.Data)
                    {
                        try
                        {
                            Te entity = (set.Where(i => Equals(i.Id, item.Id))).FirstOrDefault();

                            if (entity == default(Te))
                            {
                                entity = new Te();
                                FromService(item, entity);
                                set.Add(entity);
                            }
                            else
                            {
                                FromService(item, entity);
                            }
                            entities.SaveChanges();
                        }
                        catch (Exception ex)
                        {
                            Exceptions.Handle(ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
            }
        }

        public void Delete(DeletedRowDataRequest<Tkey> deleted)
        {
            try
            {
                using (DbContextBase<Tkey> entities = CreateContext())
                {
                    DbSet<Te> set = entities.Set<Te>();

                    foreach (Tkey key in deleted.Data)
                    {
                        try
                        {
                            Te entity = (from i in set
                                         where Equals(i.Id, key)
                                         select i).FirstOrDefault();
                            if (entity != default(Te))
                            {
                                set.Remove(entity);
                                entities.SaveChanges();
                            }
                        }
                        catch (Exception ex)
                        {
                            Exceptions.Handle(ex);
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
            }
        }
    }
}
